package lc;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

/**
 * 测试自定义加载器、父加载器，与自身加载器释放
 * 启动时：-XX:MetaspaceSize=20m -XX:MaxMetaspaceSize=20m
 */
public class OOM {

    public static void main(String[] args) {
    //    doMulti();

        doSingle();


    }

    /**
     * 可能是尝试多个jar包一起加载
     */
    private static void doMulti() {
        try{
            Thread.sleep(1000);

            int count = 0;
            while (true) {
                System.out.println("start");
//                String dir = "file:/Users/sunyuming/Documents/tool/jars/kettle_java_proxy.jar";
//                URL url = new URL(dir);
//                URL[] urls2 = {url};
//                MyUrlClassLoader myUrlClassLoader = new MyUrlClassLoader(urls2);

                File [] files = getAllJar("/Users/sunyuming/Documents/tool/jars/app/lib/");
                List<URL> urls = new ArrayList<>(files.length);
                for(File file : files) {
                    String dir = "file:" + file.getAbsolutePath();

                    URL url = new URL(dir);
                    urls.add(url);
                }

                MyUrlClassLoader myUrlClassLoader = new MyUrlClassLoader(urls.toArray(new URL[0]));

                Class CA = myUrlClassLoader.findClass("com.jds.wxtask.WxResourceJob");
                Object abstractJdsJavaJob = CA.newInstance();

                Method method = abstractJdsJavaJob.getClass().getMethod("runJdsJob", String.class, Integer.class, String.class);
                method.invoke(abstractJdsJavaJob, "", 1, "");


                System.out.println("done");
                Thread.sleep(5000);
                myUrlClassLoader = null;
                System.out.println("release");
                System.gc();

                ++ count;
                if(count > 50)
                    break;
            }

            System.out.println("alldone");
        } catch (Exception e) {
            System.out.println("found exception");
            e.printStackTrace();
        } catch (Throwable throwable) {
            System.out.println("found throwable");
            throwable.printStackTrace();
        }
    }

    /**
     * 测试
     * 1 热加载B类，B类中引用父加载器类
     * 2 抓取ClassNotFoundException
     * 3 探测类加载器释放情况，证明被热加载的类中引用系统类加载器log类不造成内存泄漏
     * 被热加载的类实例、类对象、热加载器三者都可释放
     * https://www.cnblogs.com/silyvin/p/10274898.html
     * https://www.cnblogs.com/silyvin/articles/10408310.html
     */
    private static void doSingle() {
        try{
            List<Object> list = new ArrayList<>();
            Thread.sleep(10000);

            int count = 0;
            while (true) {
                System.out.println("start");
                String dir = "file:/Users/sunyuming/Documents/tool/jars/kettle_java_proxy.jar";
                URL url = new URL(dir);
                URL[] urls2 = {url};
                MyUrlClassLoader myUrlClassLoader = new MyUrlClassLoader(urls2);
                Class<?> CA = myUrlClassLoader.loadClass("saturn.Common");
                Object o = CA.newInstance();
                Method method = CA.getMethod("run");
                method.invoke(o);
                System.out.println("done");
                Thread.sleep(5000);
                myUrlClassLoader = null;
                System.out.println("release");
                System.gc();

                ++ count;
                if(count > 5)
                    break;

                /**
                 * 这句加上后，系统类加载器hold主子加载器的实例，导致不能释放
                 */
                list.add(o);
            }

            list = null;
            System.gc();
            Thread.sleep(10000);

            System.out.println("alldone");
        } catch (Exception e) {
            System.out.println("found exception");
            e.printStackTrace();
        } catch (Throwable throwable) {
            System.out.println("found throwable");
            throwable.printStackTrace();
        }
    }



    private static class MyUrlClassLoader extends URLClassLoader {

        public MyUrlClassLoader(URL[] urls) {
            super(urls);
        }

        @Override
        protected Class<?> findClass(final String name) throws ClassNotFoundException {
            return super.findClass(name);
        }

        @Override
        protected void finalize() throws Throwable {
            System.out.println("回收");
            super.finalize();
        }
    }

    private static File[] getAllJar(String path) {
        File file = new File(path);		//获取其file对象
        File[] fs = file.listFiles();	//遍历path下的文件和目录，放在File数组中
        return fs;
    }
}